/**
 * TranslationAbstract.java
 *
 * Copyright (C) 2009,  Tomislav Milkovic
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package extjsdyntran.translation;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.Properties;
import java.util.zip.*;


import extjsdyntran.servlets.Constants;

/**
 * @description Abstract base class for translation service.
 * When creating custom translation service, new class must be extended from this one. 
 */
public abstract class TranslationAbstract  extends Configurator implements TranslationIntf {
	private static final long serialVersionUID = 1L;

	protected String username;
	protected String password;
	protected String path;
	
	protected Properties props = new Properties();


	protected  String currentLanguage = "ENGLISH";

	public TranslationAbstract(String username , String password , String path) {
		super();
		this.username = username;
		this.password = password;
		this.path = path;
	}

	private void compressSingleCache(String language, Properties lang, ZipOutputStream zout) throws Exception{
		
		ByteArrayOutputStream langout=new ByteArrayOutputStream();
		lang.store(langout, "");
		
		
        zout.putNextEntry(new ZipEntry(language + ".properties")); 
        zout.write(langout.toByteArray(),0,langout.size());
        zout.closeEntry(); 
	}
	
	public ByteArrayOutputStream compressCache(String language) throws Exception{
		ByteArrayOutputStream bout=new ByteArrayOutputStream();
		ZipOutputStream zout=new ZipOutputStream(bout);
		Properties lang = null;
		
		if (language ==null){
			Enumeration<String> keys = this.languages.keys();
			Enumeration<Properties> values = this.languages.elements();
			while (keys.hasMoreElements()){			
				String name = keys.nextElement();
				lang =  values.nextElement();
				compressSingleCache(name,lang,zout);
			}
			
			zout.finish();
			return bout;			
		}
		
		if (languages.containsKey(language)){
			lang = languages.get(language);
			compressSingleCache(language,lang,zout);
			zout.finish(); 
			return bout;
		}
	
		return bout ; 
	}
    
	

	 
	public boolean deCompressCache(byte[]  bin) throws Exception{
		
        ZipInputStream zin = new ZipInputStream(new ByteArrayInputStream(bin));
        ZipEntry zEntry = null;
        boolean result = false;
        
        while( (zEntry = zin.getNextEntry()) != null) {
           
           int size;
           byte[] buffer = new byte[1024];           
           ByteArrayOutputStream bos = new ByteArrayOutputStream();           
           
           while ((size = zin.read(buffer, 0, buffer.length)) != -1) {
        	   bos.write(buffer, 0, size);
        	   }
           
           
           String lang =  zEntry.getName();
           int whereDot = lang.lastIndexOf('.');
           String ext = lang.substring(whereDot+1,lang.length());
           lang = lang.substring(0, whereDot);
           
           if (!("properties".equals(ext))) continue;
           
           Properties language = languages.get(lang);           
           if (language == null) language = new Properties();     
           
           ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
           language.load(bis);     
           
           if (!languages.contains(language)) languages.put(lang,language);
           
           bos.close();
           bis.close();
            
           result = true;
        }
        zin.close();
		
		return result;
	}
	
	
	public static <T extends Enum<T>> String[] enumNameToStringArray(T[] values) {  
	    int i = 0;  
	    String[] result = new String[values.length];  
	    for (T value: values) {  
	        result[i++] = value.name();  
	    }  
	    return result;  
	}  
	
	public static  String[] enumerationToStringArray( Hashtable<?,?> values) {  
	    
	    String[] result = new String[values.size()];
	    int i =0;
	    Enumeration<?> keys = values.keys();
		while (keys.hasMoreElements()){
			result[i++] = (String)keys.nextElement();  
		}
		
	    return result;  
	}  

	public static String[] mergeStringArrays(String array1[], String array2[]) {
		if (array1 == null || array1.length == 0) return array2;
		if (array2 == null || array2.length == 0)return array1;
		List<String> result = new ArrayList<String>(Arrays.asList(array1));
		result.retainAll(Arrays.asList(array2));
		
		return result.toArray(new String[result.size()]);
	}
	
	//creates json array of translations [[ENGLISH:'...', language : '...' ]]
	public String getTranslations(String language) {
		try {

			Properties lang = languages.get(language);
			if (lang == null)
				return Constants.json_false;

			StringBuffer sb = new StringBuffer();
			sb.append("[");

			Enumeration<?> e1 = lang.keys();
			Enumeration<?> e2 = lang.elements();
			String value = null;
			String key = null;
			while (e1.hasMoreElements()) {
				key = (String) e1.nextElement();
				value = (String) e2.nextElement();
				sb.append("{ '");
				sb.append("ENGLISH");
				sb.append("' : '");
				sb.append(key);

				if (!"ENGLISH".equals(language)) {
					sb.append("', '");
					sb.append(language);
					sb.append("' : '");
					sb.append(value);
				}

				sb.append("'}");
				if (e1.hasMoreElements())
					sb.append(",");
			}
			sb.append("]");
			return sb.toString();

		} catch (Exception e) {
			return Constants.json_false;
		}
	}
	
	public boolean saveLanguages(String language) {

		if (language == null) {
			System.out.println("Invalid value for parameter \"language\" when trying to store.");
			return false;
		}

		System.out.println("Saving to...");
		System.out.println(path);

		if ("*".equals(language)) {
			Enumeration<String> e = languages.keys();

			try {
				while (e.hasMoreElements()) {
					String s = e.nextElement();
					Properties p = languages.get(s);
					FileOutputStream fos = new FileOutputStream(path + s + ".properties");
					p.store(fos, "");
					fos.flush();
					fos.close();
				}
				return true;
			} catch (IOException e1) {
				e1.printStackTrace();
				return false;
			}

		} else {
			try {
				Properties p = languages.get(language);
				if (p == null) {
					System.out.println("Language is unsuported : " + language);
					return false;
				}
				FileOutputStream fos = new FileOutputStream(path + language + ".properties");
				p.store(fos, "");
				fos.flush();
				fos.close();
				return true;
			} catch (IOException e1) {
				e1.printStackTrace();
				return false;
			}

		} // end else

	}
	
	protected void loadLanguages(String [] lg) {
		

		for (int i = 0; i < lg.length; i++) {
			if (lg[i].startsWith("AUTO"))
				continue;

			if (!languages.containsKey(lg[i])) {
				Properties lang = new Properties();
				languages.put(lg[i], lang);

				File file = new File(path+ lg[i] + ".properties");
				if (file.exists()) {
					try {
						FileInputStream fis = new FileInputStream(file);
						lang.load(fis);
						fis.close();
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
	

	@Override
	public Hashtable<String, Properties> getLanguagesObj() {
		return this.languages;
	}
	
}
